package com.ias.common.utils.datetime;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.TimeZone;

/**
 * 时间日期工具类
 * 提供常用的时间日期操作功能，基于Java 8+ 的时间API
 * 
 * @author IAS Platform
 * @version 1.0
 */
public class DateTimeUtil {
    
    // 常用日期时间格式
    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
    public static final String DEFAULT_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String ISO_DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
    public static final String COMPACT_DATE_FORMAT = "yyyyMMdd";
    public static final String COMPACT_DATETIME_FORMAT = "yyyyMMddHHmmss";
    public static final String CHINESE_DATE_FORMAT = "yyyy年MM月dd日";
    public static final String CHINESE_DATETIME_FORMAT = "yyyy年MM月dd日 HH时mm分ss秒";
    
    // 常用时间格式器
    private static final DateTimeFormatter DEFAULT_DATE_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT);
    private static final DateTimeFormatter DEFAULT_TIME_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT);
    private static final DateTimeFormatter DEFAULT_DATETIME_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_DATETIME_FORMAT);
    private static final DateTimeFormatter ISO_DATETIME_FORMATTER = DateTimeFormatter.ofPattern(ISO_DATETIME_FORMAT);
    private static final DateTimeFormatter COMPACT_DATE_FORMATTER = DateTimeFormatter.ofPattern(COMPACT_DATE_FORMAT);
    private static final DateTimeFormatter COMPACT_DATETIME_FORMATTER = DateTimeFormatter.ofPattern(COMPACT_DATETIME_FORMAT);
    
    // 默认时区
    private static final ZoneId DEFAULT_ZONE_ID = ZoneId.systemDefault();
    
    private DateTimeUtil() {
        // 工具类，禁止实例化
    }
    
    // ==================== 获取当前时间 ====================
    
    /**
     * 获取当前日期
     * @return 当前日期
     */
    public static LocalDate now() {
        return LocalDate.now();
    }
    
    /**
     * 获取当前时间
     * @return 当前时间
     */
    public static LocalTime nowTime() {
        return LocalTime.now();
    }
    
    /**
     * 获取当前日期时间
     * @return 当前日期时间
     */
    public static LocalDateTime nowDateTime() {
        return LocalDateTime.now();
    }
    
    /**
     * 获取当前时间戳（毫秒）
     * @return 当前时间戳
     */
    public static long nowTimestamp() {
        return System.currentTimeMillis();
    }
    
    /**
     * 获取当前时间戳（秒）
     * @return 当前时间戳（秒）
     */
    public static long nowTimestampSeconds() {
        return System.currentTimeMillis() / 1000;
    }
    
    // ==================== 时间格式化 ====================
    
    /**
     * 格式化日期为字符串（默认格式：yyyy-MM-dd）
     * @param date 日期
     * @return 格式化后的字符串
     */
    public static String formatDate(LocalDate date) {
        return formatDate(date, DEFAULT_DATE_FORMAT);
    }
    
    /**
     * 格式化日期为字符串
     * @param date 日期
     * @param pattern 格式模式
     * @return 格式化后的字符串
     */
    public static String formatDate(LocalDate date, String pattern) {
        if (date == null || pattern == null) {
            return null;
        }
        try {
            return date.format(DateTimeFormatter.ofPattern(pattern));
        } catch (Exception e) {
            System.err.println("格式化日期失败: " + e.getMessage());
            return null;
        }
    }
    
    /**
     * 格式化时间为字符串（默认格式：HH:mm:ss）
     * @param time 时间
     * @return 格式化后的字符串
     */
    public static String formatTime(LocalTime time) {
        return formatTime(time, DEFAULT_TIME_FORMAT);
    }
    
    /**
     * 格式化时间为字符串
     * @param time 时间
     * @param pattern 格式模式
     * @return 格式化后的字符串
     */
    public static String formatTime(LocalTime time, String pattern) {
        if (time == null || pattern == null) {
            return null;
        }
        try {
            return time.format(DateTimeFormatter.ofPattern(pattern));
        } catch (Exception e) {
            System.err.println("格式化时间失败: " + e.getMessage());
            return null;
        }
    }
    
    /**
     * 格式化日期时间为字符串（默认格式：yyyy-MM-dd HH:mm:ss）
     * @param dateTime 日期时间
     * @return 格式化后的字符串
     */
    public static String formatDateTime(LocalDateTime dateTime) {
        return formatDateTime(dateTime, DEFAULT_DATETIME_FORMAT);
    }
    
    /**
     * 格式化日期时间为字符串
     * @param dateTime 日期时间
     * @param pattern 格式模式
     * @return 格式化后的字符串
     */
    public static String formatDateTime(LocalDateTime dateTime, String pattern) {
        if (dateTime == null || pattern == null) {
            return null;
        }
        try {
            return dateTime.format(DateTimeFormatter.ofPattern(pattern));
        } catch (Exception e) {
            System.err.println("格式化日期时间失败: " + e.getMessage());
            return null;
        }
    }
    
    // ==================== 时间解析 ====================
    
    /**
     * 解析日期字符串（默认格式：yyyy-MM-dd）
     * @param dateStr 日期字符串
     * @return 解析后的日期
     */
    public static LocalDate parseDate(String dateStr) {
        return parseDate(dateStr, DEFAULT_DATE_FORMAT);
    }
    
    /**
     * 解析日期字符串
     * @param dateStr 日期字符串
     * @param pattern 格式模式
     * @return 解析后的日期
     */
    public static LocalDate parseDate(String dateStr, String pattern) {
        if (dateStr == null || dateStr.trim().isEmpty() || pattern == null) {
            return null;
        }
        try {
            return LocalDate.parse(dateStr.trim(), DateTimeFormatter.ofPattern(pattern));
        } catch (DateTimeParseException e) {
            System.err.println("解析日期失败: " + dateStr + ", 格式: " + pattern + ", 错误: " + e.getMessage());
            return null;
        }
    }
    
    /**
     * 解析时间字符串（默认格式：HH:mm:ss）
     * @param timeStr 时间字符串
     * @return 解析后的时间
     */
    public static LocalTime parseTime(String timeStr) {
        return parseTime(timeStr, DEFAULT_TIME_FORMAT);
    }
    
    /**
     * 解析时间字符串
     * @param timeStr 时间字符串
     * @param pattern 格式模式
     * @return 解析后的时间
     */
    public static LocalTime parseTime(String timeStr, String pattern) {
        if (timeStr == null || timeStr.trim().isEmpty() || pattern == null) {
            return null;
        }
        try {
            return LocalTime.parse(timeStr.trim(), DateTimeFormatter.ofPattern(pattern));
        } catch (DateTimeParseException e) {
            System.err.println("解析时间失败: " + timeStr + ", 格式: " + pattern + ", 错误: " + e.getMessage());
            return null;
        }
    }
    
    /**
     * 解析日期时间字符串（默认格式：yyyy-MM-dd HH:mm:ss）
     * @param dateTimeStr 日期时间字符串
     * @return 解析后的日期时间
     */
    public static LocalDateTime parseDateTime(String dateTimeStr) {
        return parseDateTime(dateTimeStr, DEFAULT_DATETIME_FORMAT);
    }
    
    /**
     * 解析日期时间字符串
     * @param dateTimeStr 日期时间字符串
     * @param pattern 格式模式
     * @return 解析后的日期时间
     */
    public static LocalDateTime parseDateTime(String dateTimeStr, String pattern) {
        if (dateTimeStr == null || dateTimeStr.trim().isEmpty() || pattern == null) {
            return null;
        }
        try {
            return LocalDateTime.parse(dateTimeStr.trim(), DateTimeFormatter.ofPattern(pattern));
        } catch (DateTimeParseException e) {
            System.err.println("解析日期时间失败: " + dateTimeStr + ", 格式: " + pattern + ", 错误: " + e.getMessage());
            return null;
        }
    }
    
    // ==================== 时间戳转换 ====================
    
    /**
     * 时间戳转LocalDateTime（毫秒）
     * @param timestamp 时间戳（毫秒）
     * @return LocalDateTime
     */
    public static LocalDateTime timestampToDateTime(long timestamp) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), DEFAULT_ZONE_ID);
    }
    
    /**
     * 时间戳转LocalDateTime（秒）
     * @param timestampSeconds 时间戳（秒）
     * @return LocalDateTime
     */
    public static LocalDateTime timestampSecondsToDateTime(long timestampSeconds) {
        return LocalDateTime.ofInstant(Instant.ofEpochSecond(timestampSeconds), DEFAULT_ZONE_ID);
    }
    
    /**
     * LocalDateTime转时间戳（毫秒）
     * @param dateTime 日期时间
     * @return 时间戳（毫秒）
     */
    public static long dateTimeToTimestamp(LocalDateTime dateTime) {
        if (dateTime == null) {
            return 0;
        }
        return dateTime.atZone(DEFAULT_ZONE_ID).toInstant().toEpochMilli();
    }
    
    /**
     * LocalDateTime转时间戳（秒）
     * @param dateTime 日期时间
     * @return 时间戳（秒）
     */
    public static long dateTimeToTimestampSeconds(LocalDateTime dateTime) {
        if (dateTime == null) {
            return 0;
        }
        return dateTime.atZone(DEFAULT_ZONE_ID).toInstant().getEpochSecond();
    }
    
    // ==================== Date与LocalDateTime转换 ====================
    
    /**
     * Date转LocalDateTime
     * @param date Date对象
     * @return LocalDateTime
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        if (date == null) {
            return null;
        }
        return LocalDateTime.ofInstant(date.toInstant(), DEFAULT_ZONE_ID);
    }
    
    /**
     * LocalDateTime转Date
     * @param dateTime LocalDateTime对象
     * @return Date
     */
    public static Date localDateTimeToDate(LocalDateTime dateTime) {
        if (dateTime == null) {
            return null;
        }
        return Date.from(dateTime.atZone(DEFAULT_ZONE_ID).toInstant());
    }
    
    /**
     * Date转LocalDate
     * @param date Date对象
     * @return LocalDate
     */
    public static LocalDate dateToLocalDate(Date date) {
        if (date == null) {
            return null;
        }
        return date.toInstant().atZone(DEFAULT_ZONE_ID).toLocalDate();
    }
    
    /**
     * LocalDate转Date
     * @param date LocalDate对象
     * @return Date
     */
    public static Date localDateToDate(LocalDate date) {
        if (date == null) {
            return null;
        }
        return Date.from(date.atStartOfDay(DEFAULT_ZONE_ID).toInstant());
    }
    
    // ==================== 时间计算 ====================
    
    /**
     * 日期加天数
     * @param date 日期
     * @param days 天数
     * @return 新日期
     */
    public static LocalDate plusDays(LocalDate date, long days) {
        return date == null ? null : date.plusDays(days);
    }
    
    /**
     * 日期减天数
     * @param date 日期
     * @param days 天数
     * @return 新日期
     */
    public static LocalDate minusDays(LocalDate date, long days) {
        return date == null ? null : date.minusDays(days);
    }
    
    /**
     * 日期时间加天数
     * @param dateTime 日期时间
     * @param days 天数
     * @return 新日期时间
     */
    public static LocalDateTime plusDays(LocalDateTime dateTime, long days) {
        return dateTime == null ? null : dateTime.plusDays(days);
    }
    
    /**
     * 日期时间减天数
     * @param dateTime 日期时间
     * @param days 天数
     * @return 新日期时间
     */
    public static LocalDateTime minusDays(LocalDateTime dateTime, long days) {
        return dateTime == null ? null : dateTime.minusDays(days);
    }
    
    /**
     * 日期时间加小时
     * @param dateTime 日期时间
     * @param hours 小时数
     * @return 新日期时间
     */
    public static LocalDateTime plusHours(LocalDateTime dateTime, long hours) {
        return dateTime == null ? null : dateTime.plusHours(hours);
    }
    
    /**
     * 日期时间减小时
     * @param dateTime 日期时间
     * @param hours 小时数
     * @return 新日期时间
     */
    public static LocalDateTime minusHours(LocalDateTime dateTime, long hours) {
        return dateTime == null ? null : dateTime.minusHours(hours);
    }
    
    /**
     * 日期时间加分钟
     * @param dateTime 日期时间
     * @param minutes 分钟数
     * @return 新日期时间
     */
    public static LocalDateTime plusMinutes(LocalDateTime dateTime, long minutes) {
        return dateTime == null ? null : dateTime.plusMinutes(minutes);
    }
    
    /**
     * 日期时间减分钟
     * @param dateTime 日期时间
     * @param minutes 分钟数
     * @return 新日期时间
     */
    public static LocalDateTime minusMinutes(LocalDateTime dateTime, long minutes) {
        return dateTime == null ? null : dateTime.minusMinutes(minutes);
    }
    
    // ==================== 时间比较 ====================
    
    /**
     * 判断日期是否在指定日期之前
     * @param date1 日期1
     * @param date2 日期2
     * @return true if date1 < date2
     */
    public static boolean isBefore(LocalDate date1, LocalDate date2) {
        if (date1 == null || date2 == null) {
            return false;
        }
        return date1.isBefore(date2);
    }
    
    /**
     * 判断日期是否在指定日期之后
     * @param date1 日期1
     * @param date2 日期2
     * @return true if date1 > date2
     */
    public static boolean isAfter(LocalDate date1, LocalDate date2) {
        if (date1 == null || date2 == null) {
            return false;
        }
        return date1.isAfter(date2);
    }
    
    /**
     * 判断日期时间是否在指定日期时间之前
     * @param dateTime1 日期时间1
     * @param dateTime2 日期时间2
     * @return true if dateTime1 < dateTime2
     */
    public static boolean isBefore(LocalDateTime dateTime1, LocalDateTime dateTime2) {
        if (dateTime1 == null || dateTime2 == null) {
            return false;
        }
        return dateTime1.isBefore(dateTime2);
    }
    
    /**
     * 判断日期时间是否在指定日期时间之后
     * @param dateTime1 日期时间1
     * @param dateTime2 日期时间2
     * @return true if dateTime1 > dateTime2
     */
    public static boolean isAfter(LocalDateTime dateTime1, LocalDateTime dateTime2) {
        if (dateTime1 == null || dateTime2 == null) {
            return false;
        }
        return dateTime1.isAfter(dateTime2);
    }
    
    // ==================== 时间差计算 ====================
    
    /**
     * 计算两个日期之间的天数差
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 天数差
     */
    public static long daysBetween(LocalDate startDate, LocalDate endDate) {
        if (startDate == null || endDate == null) {
            return 0;
        }
        return ChronoUnit.DAYS.between(startDate, endDate);
    }
    
    /**
     * 计算两个日期时间之间的天数差
     * @param startDateTime 开始日期时间
     * @param endDateTime 结束日期时间
     * @return 天数差
     */
    public static long daysBetween(LocalDateTime startDateTime, LocalDateTime endDateTime) {
        if (startDateTime == null || endDateTime == null) {
            return 0;
        }
        return ChronoUnit.DAYS.between(startDateTime, endDateTime);
    }
    
    /**
     * 计算两个日期时间之间的小时差
     * @param startDateTime 开始日期时间
     * @param endDateTime 结束日期时间
     * @return 小时差
     */
    public static long hoursBetween(LocalDateTime startDateTime, LocalDateTime endDateTime) {
        if (startDateTime == null || endDateTime == null) {
            return 0;
        }
        return ChronoUnit.HOURS.between(startDateTime, endDateTime);
    }
    
    /**
     * 计算两个日期时间之间的分钟差
     * @param startDateTime 开始日期时间
     * @param endDateTime 结束日期时间
     * @return 分钟差
     */
    public static long minutesBetween(LocalDateTime startDateTime, LocalDateTime endDateTime) {
        if (startDateTime == null || endDateTime == null) {
            return 0;
        }
        return ChronoUnit.MINUTES.between(startDateTime, endDateTime);
    }
    
    /**
     * 计算两个日期时间之间的秒数差
     * @param startDateTime 开始日期时间
     * @param endDateTime 结束日期时间
     * @return 秒数差
     */
    public static long secondsBetween(LocalDateTime startDateTime, LocalDateTime endDateTime) {
        if (startDateTime == null || endDateTime == null) {
            return 0;
        }
        return ChronoUnit.SECONDS.between(startDateTime, endDateTime);
    }
    
    // ==================== 特殊日期获取 ====================
    
    /**
     * 获取指定日期所在月份的第一天
     * @param date 日期
     * @return 月份第一天
     */
    public static LocalDate getFirstDayOfMonth(LocalDate date) {
        return date == null ? null : date.with(TemporalAdjusters.firstDayOfMonth());
    }
    
    /**
     * 获取指定日期所在月份的最后一天
     * @param date 日期
     * @return 月份最后一天
     */
    public static LocalDate getLastDayOfMonth(LocalDate date) {
        return date == null ? null : date.with(TemporalAdjusters.lastDayOfMonth());
    }
    
    /**
     * 获取指定日期所在年份的第一天
     * @param date 日期
     * @return 年份第一天
     */
    public static LocalDate getFirstDayOfYear(LocalDate date) {
        return date == null ? null : date.with(TemporalAdjusters.firstDayOfYear());
    }
    
    /**
     * 获取指定日期所在年份的最后一天
     * @param date 日期
     * @return 年份最后一天
     */
    public static LocalDate getLastDayOfYear(LocalDate date) {
        return date == null ? null : date.with(TemporalAdjusters.lastDayOfYear());
    }
    
    /**
     * 获取指定日期时间当天的开始时间（00:00:00）
     * @param dateTime 日期时间
     * @return 当天开始时间
     */
    public static LocalDateTime getStartOfDay(LocalDateTime dateTime) {
        return dateTime == null ? null : dateTime.toLocalDate().atStartOfDay();
    }
    
    /**
     * 获取指定日期时间当天的结束时间（23:59:59.999999999）
     * @param dateTime 日期时间
     * @return 当天结束时间
     */
    public static LocalDateTime getEndOfDay(LocalDateTime dateTime) {
        return dateTime == null ? null : dateTime.toLocalDate().atTime(LocalTime.MAX);
    }
    
    // ==================== 时间验证 ====================
    
    /**
     * 判断是否是闰年
     * @param year 年份
     * @return true if 闰年
     */
    public static boolean isLeapYear(int year) {
        return Year.of(year).isLeap();
    }
    
    /**
     * 判断日期是否是今天
     * @param date 日期
     * @return true if 今天
     */
    public static boolean isToday(LocalDate date) {
        return date != null && date.equals(LocalDate.now());
    }
    
    /**
     * 判断日期时间是否是今天
     * @param dateTime 日期时间
     * @return true if 今天
     */
    public static boolean isToday(LocalDateTime dateTime) {
        return dateTime != null && dateTime.toLocalDate().equals(LocalDate.now());
    }
    
    /**
     * 判断日期是否是周末
     * @param date 日期
     * @return true if 周末
     */
    public static boolean isWeekend(LocalDate date) {
        if (date == null) {
            return false;
        }
        DayOfWeek dayOfWeek = date.getDayOfWeek();
        return dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY;
    }
    
    // ==================== 时区转换 ====================
    
    /**
     * 转换时区
     * @param dateTime 日期时间
     * @param fromZone 源时区
     * @param toZone 目标时区
     * @return 转换后的日期时间
     */
    public static LocalDateTime convertTimeZone(LocalDateTime dateTime, ZoneId fromZone, ZoneId toZone) {
        if (dateTime == null || fromZone == null || toZone == null) {
            return dateTime;
        }
        return dateTime.atZone(fromZone).withZoneSameInstant(toZone).toLocalDateTime();
    }
    
    /**
     * 转换为UTC时间
     * @param dateTime 本地日期时间
     * @return UTC时间
     */
    public static LocalDateTime toUTC(LocalDateTime dateTime) {
        return convertTimeZone(dateTime, DEFAULT_ZONE_ID, ZoneOffset.UTC);
    }
    
    /**
     * 从UTC时间转换为本地时间
     * @param utcDateTime UTC日期时间
     * @return 本地时间
     */
    public static LocalDateTime fromUTC(LocalDateTime utcDateTime) {
        return convertTimeZone(utcDateTime, ZoneOffset.UTC, DEFAULT_ZONE_ID);
    }
    
    // ==================== 工具方法 ====================
    
    /**
     * 获取年龄
     * @param birthDate 出生日期
     * @return 年龄
     */
    public static int getAge(LocalDate birthDate) {
        if (birthDate == null) {
            return 0;
        }
        return (int) ChronoUnit.YEARS.between(birthDate, LocalDate.now());
    }
    
    /**
     * 获取指定日期是星期几
     * @param date 日期
     * @return 星期几（1-7，1表示星期一）
     */
    public static int getDayOfWeek(LocalDate date) {
        return date == null ? 0 : date.getDayOfWeek().getValue();
    }
    
    /**
     * 获取指定日期是一年中的第几天
     * @param date 日期
     * @return 一年中的第几天
     */
    public static int getDayOfYear(LocalDate date) {
        return date == null ? 0 : date.getDayOfYear();
    }
    
    /**
     * 获取指定日期所在月份的天数
     * @param date 日期
     * @return 月份天数
     */
    public static int getDaysInMonth(LocalDate date) {
        return date == null ? 0 : date.lengthOfMonth();
    }
    
    /**
     * 获取指定年份的天数
     * @param year 年份
     * @return 年份天数
     */
    public static int getDaysInYear(int year) {
        return Year.of(year).length();
    }
    
    /**
     * 格式化持续时间为易读字符串
     * @param duration 持续时间（毫秒）
     * @return 格式化后的字符串，如："2天3小时5分钟"
     */
    public static String formatDuration(long duration) {
        if (duration < 0) {
            return "0毫秒";
        }
        
        long days = duration / (24 * 60 * 60 * 1000);
        long hours = (duration % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000);
        long minutes = (duration % (60 * 60 * 1000)) / (60 * 1000);
        long seconds = (duration % (60 * 1000)) / 1000;
        long millis = duration % 1000;
        
        StringBuilder sb = new StringBuilder();
        if (days > 0) sb.append(days).append("天");
        if (hours > 0) sb.append(hours).append("小时");
        if (minutes > 0) sb.append(minutes).append("分钟");
        if (seconds > 0) sb.append(seconds).append("秒");
        if (millis > 0 && sb.length() == 0) sb.append(millis).append("毫秒");
        
        return sb.length() > 0 ? sb.toString() : "0毫秒";
    }
}
